# This file is part of the 'dragora-installer'.
#
# Purpose: Set Linux partition(s) and mount points.

# Add or refresh list of partitions taking initial
# list of partitions and temporary fstab into account
makeMenu()
{
    while read -r line
    do
        test -n "$line" || continue

        # Get device name and size

        device="${line%% *}"
        size="$(lsblk --noheadings --nodeps --output SIZE "$device")"

        # Get device mount point and file system type

        devpoint="$(awk -v patr="$device" '$1 == patr { print $2 }' \
                     "${SUBTMPDIR}/fstab" 2> /dev/null)"
        formatfs="$(awk -v patr="$device" '$1 == patr { print $3 }' \
                     "${SUBTMPDIR}/fstab" 2> /dev/null)"

        if test -z "$formatfs" || test "$formatfs" = defaults
        then
            formatfs="$(blkid -s TYPE -o value "$device" 2> /dev/null)"
        fi

        # Write entry to be showed on the MakeFS menu

        echo "\"${device}\" \"${formatfs:-Linux}${size} $devpoint\" \\" \
         >> "${SUBTMPDIR}/MakeFS"

    done < "${SUBTMPDIR}/partitions"

    # End Of
    echo ' 2> "${SUBTMPDIR}/return-MakeFS" || _code=$?' \
     >> "${SUBTMPDIR}/MakeFS"
}

# Ask to assign a valid mount point
askMountPoint()
{
    dialog --colors \
     --backtitle "\\ZbSetting Linux partitions: Mount point for $1" \
     --title "MOUNT POINT" \
     --no-cancel --ok-label "Continue" \
     --cr-wrap --inputbox \
"A mount point can be assigned to the partition.

* Consider declaring a complete path such as \"/storage\".
* If you declare the single slash \"/\" it will be
  designated for the (main) system partition.

Note: If you use directory names that contain spaces,
the same will be converted using the octal character
040, which is interpreted by the file system table.

Enter a mount point for \"${1}\":
(If you leave this blank, any previous entries will be deleted)." 20 62 \
     2> "${SUBTMPDIR}/return-MakeFS_askMountPoint" || return 0

    # We remove possible single/double quotes from the answer.
    # Also we convert any blank space (tab or space) into the
    # octal space character (040) to be handled by fstab(5).
    # This is in case that the user introduce a directory with
    # blank spaces.  We are not managing the octal tab character
    # (011) since TAB is a functional key in dialog(1).

    mntpoint="$(sed -e "s/[\\'\"]//g" -e 's/[[:blank:]]/\\040/g' \
                  "${SUBTMPDIR}/return-MakeFS_askMountPoint")"

    if test -n "$mntpoint"
    then
        # Determine the sixth field for the fstab
        case $mntpoint in
        /)  fs_passno=1;;
        *)  fs_passno=2;;
        esac

        # Refresh file system type information
        formatfs="$(blkid -s TYPE -o value "$1" 2> /dev/null)"

        # Write fstab entry

        printf '%-43s %-14s %-12s %-16s %-3s %s\n' \
         "$1" "$mntpoint" "$formatfs" "defaults" "1" "${fs_passno}" \
         >> "${SUBTMPDIR}/fstab"

        unset -v fs_passno formatfs

        # Remove possible duplicates
        if test "$(grep -c "^$1" "${SUBTMPDIR}"/fstab)" -gt 1
        then
            repeated="$(grep -m 1 -n "^$1" "${SUBTMPDIR}"/fstab)"
            repeated="${repeated%%:*}"
            sed -i "${repeated}d" "${SUBTMPDIR}/fstab"
            unset -v repeated
        fi
    else # Remove the whole fstab entry
        if test -n "$1" && test -s "${SUBTMPDIR}/fstab"
        then
            escape_slash="$(printf '%s' "$1" | sed 's/\//\\\//g')"
            sed -i "/${escape_slash}/d" "${SUBTMPDIR}/fstab"
            unset -v escape_slash
        fi
    fi
    unset -v mntpoint
}

_mkfs()
{
    helper="$1"
    devname="$2"

    dialog --colors \
     --backtitle "\\ZbPartitions - ${devname}" \
     --title "FILE SYSTEM FORMAT" \
     --ok-label "Format" --cr-wrap --checklist \
"The following device can be formatted using the \"${helper}\" helper:

$(fdisk -l "$devname" | head -n 1)" 13 55 1 \
"$devname"    "Check for bad blocks (slow)" off \
    2> "${SUBTMPDIR}/return-MakeFS_mkfs" || return $?

    dialog --clear

    echo "Making ${helper#*.} filesystem for $devname ..."
    echo ""

    if test -s "${SUBTMPDIR}/return-MakeFS_mkfs"
    then
        $helper -F -F -c $devname
    else
        $helper -F -F $devname
    fi
    sleep 4

    unset -v helper devname
}

_mkbtrfs()
{
    dialog --clear

    echo "Making btrfs filesystem for $1 ..."
    echo ""

    mkfs.btrfs -f -d single -m single "$1"
    sleep 4
}

_mkreiser4()
{
    # Check if the device name is a SDD
    case $1 in
    *nvme*)
        reiser_sdd=-d
        ;;
    esac

    dialog --clear

    echo "Making reiser4 filesystem for $1 ..."
    echo ""

    mkfs.reiser4 -yf $reiser_sdd -o create=reg40,node=node41 "$1"
    sleep 4

    unset -v reiser_sdd
}

_mkxfs()
{
    dialog --clear

    echo "Making xfs filesystem for $1 ..."
    echo ""

    mkfs.xfs -f "$1"
    sleep 4
}

formatMenu()
{
    dialog --colors \
     --backtitle "\\Zb${1}: Setting a file system" \
     --title "FILE SYSTEM SELECTION" \
     --default-item "ext3" \
     --item-help --cr-wrap --menu \
"Choose a file system for '${1}':" 13 58 6 \
"ext2"     "Second extended filesystem"       "ext2 remains the preferred file system for flash-based storage media due to its lack of a journal" \
"ext3"     "Third  extended filesystem"       "ext3 is suitable for both 32-bit and 64-bit systems" \
"ext4"     "Fourth extended filesystem"       "We suggest using it more for a 64-bit system than for a 32-bit system" \
"btrfs"    "Btrfs filesystem"                 "A modern copy on write (CoW) filesystem for GNU/Linux" \
"reiser4"  "Reiser4 filesystem"               "Reiser4 is a successor of ReiserFS (a general-purpose, journaling file system)" \
"xfs"      "XFS filesystem"                   "XFS is a high-performance 64-bit journaling file system suitable for real-time applications" \
    2> "${SUBTMPDIR}/return-MakeFS_formatMenu" || _status=$?

    if test -n "$_status" && test $_status -ne 0
    then
        return "$_status";
    fi
    unset -v _status

    # Try to unmount the device if it is already mounted
    umount "$1" > /dev/null 2>&1 || true

    # Check for selected options to give the proper format
    case "$(cat -- "${SUBTMPDIR}"/return-MakeFS_formatMenu)" in
    ext2)
        _mkfs mkfs.ext2 "$1"
        ;;
    ext3)
        _mkfs mkfs.ext3 "$1"
        ;;
    ext4)
        _mkfs mkfs.ext4 "$1"
        ;;
    btrfs)
        _mkbtrfs "$1"
        ;;
    reiser4)
        _mkreiser4 "$1"
        ;;
    xfs)
        _mkxfs "$1"
        ;;
    esac
}

# Compose partition menu to be displayed

while true
do
    cat << EOF > "${SUBTMPDIR}/MakeFS"
dialog --colors \\
 --backtitle "\\ZbPartitions and mount points" \\
 --title "Setting Linux partitions" \\
 --ok-button "Establish" --extra-button \\
 --extra-label "Done" \\
 --cr-wrap --menu \\
"The following Linux partitions has been detected:

    Selecting a partition gives you the possibility to set up
a file system or a mount point for the boot stage of the system.
Once this has been established, choose the \\"Done\\" button
to continue with the installation." 16 65 5 \\
EOF
    makeMenu && . "${SUBTMPDIR}/MakeFS"
    case "${_code:-$?}" in
    0)
        partition="$(cat -- "${SUBTMPDIR}"/return-MakeFS)"

        if test -z "$partition"
        then
            echo "${PROGRAM}: Error the partition list is empty." 1>&2
            exit 99;
        fi

        if test -n "$(blkid -s TYPE -o value "$partition" 2> /dev/null)"
        then
            dialog --colors \
             --backtitle "\\ZbPartitions and mount points" \
             --title "$partition" \
             --no-cancel --cr-wrap --menu \
"Selected device already contains a file system!

You can assign a mount point for system startup, you also
have the ability to re-format the partition.  If you choose
the latter, you will lose all your data and will be asked
for a mounting point.

What would you like to do for '${partition}'?" 17 64 3 \
             "0" "Assign a mount point" \
             "1" "Format again (data loss risk)" \
             "<" "Return to previous menu" \
            2> "${SUBTMPDIR}/return-MakeFS_case" || continue;

            case "$(cat -- "${SUBTMPDIR}"/return-MakeFS_case)" in
            0)  askMountPoint "$partition";;
            1)  formatMenu "$partition" && askMountPoint "$partition";;
            esac
        else
            formatMenu "$partition" && askMountPoint "$partition"
        fi
        ;;
    3)
        # To verify the existence of the designated system mount point
        if grep -qs -m 1 '/ ' "${SUBTMPDIR}/fstab"
        then
            break;
        else
            dialog --colors \
             --backtitle "\\ZbPartitions and mount points: Unknown mount point for root partition" \
             --title "NO MOUNT POINT FOR MAIN SYSTEM" \
             --ok-label "Return" --cr-wrap --msgbox \
"
There is no declared mount point for the root partition.

    Please go back and assign a mount point for the
root partition.  Remember that the mount point must
be declared as \"/\" (without quotes and spaces).
" 11 60 || { unset -v _code ; continue; }
        fi
        ;;
    *)
        exit "$_code"
        ;;
    esac
    unset -v _code;	# To take the value again.
done

unset makeMenu _mkfs _mkxfs FormatMenu _code

